import qs from 'qs'
import AES from 'crypto-js/aes'
import MD5 from 'crypto-js/md5'
import ENCUTF8 from 'crypto-js/enc-utf8'
import ENCBASE64 from 'crypto-js/enc-base64'
import { UseFetchOptions } from 'nuxt/app'
import $dayjs from './dayjs'

type Methods = 'GET' | 'POST' | 'DELETE' | 'PUT'

const CODE_MSG: any = {
  4100: 'UnknownError',
  4101: 'RequestFailed',
  4001: 'APINotFound',
  4002: 'ParamError',
  4003: 'NotLogin',
  4004: 'UserTypeError',
  4005: 'NotHavePermissions',
  4006: 'SigTimeExpired',
  4007: 'ImageCodeError',
  5000: 'ServerInternalError',
  5001: 'DataError',
  5003: 'ServerNotAvailable',
  6000: 'RecordNotFound',
  6001: 'VerifyFailed',
  6002: 'CoinsNotEnough',
  6003: 'PaymentAmountInvalid',
  6004: 'PaymentNotFinished',
  6005: 'PaymentOrderIDInvalid',
  6006: 'EmailChangeNotSupport',
  6007: 'HasBeenKickedOut',
  6008: 'EmailNotAvailable',
  6009: 'UserInExistence',
  6010: 'RepeatUnlock',
  // 6011: 'FilmNoPay',
  6012: 'FilmExpired',
  6013: 'FilmFree',
  7001: 'FilmOffShelf',
  8001: 'GiftGot',
  8002: 'HasBeenCheckedIn',
  8003: 'CheckedInDateIllegal',
  8004: 'TaskHasDone',
  8005: 'TaskInConformity',
  8006: 'PaymentOrderOutOfLimit',
}

class HttpRequest {
  request<T = any>(url: string, method: Methods, data?: any, options?: UseFetchOptions<T>): any {
    const userStore = localStorage.getItem('userinfo') ?? `{}`
    const userInfo = JSON.parse(userStore)
    return new Promise((resolve, reject) => {
      const config = useRuntimeConfig()
      const newOptions: UseFetchOptions<T> = {
        baseURL: config.public.apiBaseUrl,
        method,
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'Auth-Token': userInfo?.token || '',
        },
        ...options,
        timeout: 30000,
      }
      if (method === 'GET' || method === 'DELETE') {
        newOptions.params = data
      }
      if (method === 'POST' || method === 'PUT') {
        newOptions.body = data
      }

      useFetch(url, newOptions)
        .then(res => {
          const resJson: any = res.data?.value ?? '{}'
          const resData = JSON.parse(resJson as string)
          const { Code } = resData
          if (Code === 0) {
            resolve(resData)
          } else if (url !== '/GetUserInfo') {
            if (Object.keys(CODE_MSG).includes(Code)) {
              showToast({
                type: 'html',
                message: `<span class="text-danger">${CODE_MSG[Code]}</span>`,
              })
            }
            resolve(resData)
          }
        })
        .catch(error => {
          reject(error)
        })
    })
  }

  // 签名api和参数
  getSigStr(path: string, params: any, token = 'fZ9&N6ufs4gACs@a') {
    const paramsObject = qs.parse(params)
    const paramsArr = Object.keys(paramsObject)
    paramsArr.sort()

    let str = path.startsWith('/') ? path.slice(1) : path
    paramsArr.forEach(paramKey => {
      str += `${paramKey}=${paramsObject[paramKey]}`
    })

    str += token
    return MD5(str).toString().toUpperCase()
  }

  // 加密设备数据
  getDeviceAes() {
    const userStore = localStorage.getItem('userinfo') ?? `{}`
    const devStore = localStorage.getItem('chinfo') ?? `{}`
    const userInfo = JSON.parse(userStore)
    const devInfo = JSON.parse(devStore)
    const deviceInfo: any = {
      ch: devInfo.ch || 'STV8678',
      zch: '',
      reqSource: 'h5',
      code: devInfo.code,
    }

    // 如果有用户信息，提交给deviceId
    if (userInfo?.email) {
      deviceInfo.deviceId = MD5(userInfo?.email)
        .toString()
        .toUpperCase()
    }
    const str = qs.stringify(deviceInfo)
    const sigStr = this.encrypt(str)
    return sigStr
  }

  encrypt(str: string, key = 'fZ9&N6ufs4gACs@a') {
    const encrypted = AES.encrypt(str, ENCUTF8.parse(key), {
      iv: ENCUTF8.parse(key),
    })
    return encrypted.ciphertext.toString(ENCBASE64)
  }

  decrypt(encrypted: any, key = 'fZ9&N6ufs4gACs@d') {
    const decrypted = AES.decrypt(encrypted, ENCUTF8.parse(key), {
      iv: ENCUTF8.parse(key),
    })
    return decrypted.toString(ENCUTF8)
  }

  // 封装常用方法
  get<T = any>(url: string, params?: any, options?: UseFetchOptions<T>) {
    return this.request(url, 'GET', params, options)
  }

  post<T = any>(url: string, data?: any, options?: UseFetchOptions<T>) {
    const userStore = localStorage.getItem('userinfo') ?? `{}`
    const userInfo = JSON.parse(userStore)

    const bodyData = {
      ...data,
      param: this.getDeviceAes(),
      t: $dayjs().unix(),
    }
    bodyData.sig = this.getSigStr(url, bodyData, userInfo?.token || undefined)

    return this.request(url, 'POST', qs.stringify(bodyData), options)
  }
}

export const useRequest = new HttpRequest()
